using System.Collections.Generic;
using System.Linq;
using Lucene.Net.Analysis.Snowball;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Util;
using NopSolutions.NopCommerce.BusinessLogic.Products;
using NopSolutions.NopCommerce.BusinessLogic.Products.Specs;

namespace NopSolutions.NopCommerce.LuceneHelper.Queries
{
    public class ProductQuery : BaseQuery<ProductQuery>
    {
        public ProductQuery(Query query)
            : base(query)
        {
        }
        public ProductQuery()
        {
        }


        public ProductQuery WithManufacturers(IList<int> manufacturers)
        {
            Query = JoinQueries(Query, GetQueryFromList(manufacturers, "ManufacturerID"));
            return this;
        }

        public ProductQuery WithCategories(IList<int> categories)
        {
            Query = JoinQueries(Query, GetQueryFromList(categories, "CategoryID"));
            return this;
        }

        public ProductQuery WithSpecifications(IList<int> specifications)
        {
            Query = JoinQueries(Query, GetQueryFromList(specifications, "Specification"));
            return this;
        }
        public ProductQuery WithSpecifications(IList<SpecificationAttribute> specifications)
        {
            return WithSpecifications(specifications.Select(x => x.SpecificationAttributeId).ToList());
        }
        public ProductQuery WithSpecification(SpecificationAttribute specification)
        {
            return WithSpecification(specification.SpecificationAttributeId);
        }
        public ProductQuery WithSpecification(int specificationId)
        {
            return WithSpecifications(new List<int>{specificationId});
        }

        

        public ProductQuery WithSpecificationsOptions(IList<SpecificationAttributeOption> specifications)
        {
            Query = JoinQueries(Query,
                GetQueryFromList<SpecificationAttributeOption>(specifications,
                    key => "Spec" + key.SpecificationAttributeId.ToString(),
                    value => value.SpecificationAttributeOptionId.ToString()));
            return this;
        }

        public ProductQuery WithSpecificationsOption(SpecificationAttributeOption specification)
        {
            return WithSpecificationsOptions(new List<SpecificationAttributeOption> { specification });
        }

        public ProductQuery WithSpecificationsOption(int specificationId, int specificationOptionId)
        {
            return
                WithSpecificationsOption(new SpecificationAttributeOption
                                             {
                                                 SpecificationAttributeId = specificationId,
                                                 SpecificationAttributeOptionId = specificationOptionId
                                             });
        }

        public ProductQuery WithProductID(int productId)
        {
            Query = JoinQueries(Query, new TermQuery(new Term("ProductID", productId.ToString())));
            return this;
        }

        public ProductQuery WithPriceBetween(PriceRange priceRange)
        {
            if (priceRange != null)
            {
                if (priceRange.To != null || priceRange.From != null)
                {
                    var rangeFilter = NumericRangeQuery.NewFloatRange("Price",
                        priceRange.From.HasValue ? (float)priceRange.From.Value : 0,
                        priceRange.To.HasValue ? (float)priceRange.To.Value : float.MaxValue, 
                        true, 
                        true);
               
                    Query = JoinQueries(Query, rangeFilter);
                }
            }
            return this;
        }

        public ProductQuery WithKeywords(string keywords)
        {
            if (!string.IsNullOrEmpty(keywords))
            {
                string[] fields = { "FullDescription", "Name" };
                var q = new MultiFieldQueryParser(Version.LUCENE_29, fields, new SnowballAnalyzer("English", Globals.StopWords()));
                var query = q.Parse(keywords);
                Query = JoinQueries(Query, query);
            }
            return this;
        }

        public ProductQuery WithFilterContext(FilterContext context)
        {
            if (context.Categories.Any())
                WithCategories(context.Categories);
            if(context.Filters.Any())
                WithSpecificationsOptions(context.Filters);
            if (!string.IsNullOrEmpty(context.KeyWords))
                WithKeywords(context.KeyWords);
            if (context.Manufacturers.Any())
                WithManufacturers(context.Manufacturers);
            if(context.PriceRange != null && (context.PriceRange.From.HasValue || context.PriceRange.To.HasValue))
                WithPriceBetween(context.PriceRange);
            return this;
        }


        public override LuceneIndexType IndexType
        {
            get { return LuceneIndexType.Product; }
        }
    }
}
